class EventManager {
  static Register(key, eventFunction, context) {
    this.GetEvent(key).Add(new Observer(eventFunction, context));
  }

  static UnRegister(key, context) {
    this.GetEvent(key).Remove(context);
  }

  static UnRegisterAll(key) {
    this.GetEvent(key).RemoveAll();
  }

  static Send(key, ...params) {
    this.GetEvent(key).Send(...params);
  }

  static Recycle() {
    if (this.eventDict != null) {
      for (var k in this.eventDict) {
        this.eventDict[k].RemoveAll();
      }
    }
    this.eventDict = {};
  }

  static GetEvent(key) {
    if (!this.eventDict) { this.eventDict = []; }
    var event = new Event();
    if (this.eventDict != null) {
      for (var k in this.eventDict) {
        if (k == key) {
          event = this.eventDict[k];
          return event;
        }
      }
    }
    this.eventDict[key] = event;
    return event;
  }
}

class Observer {
  constructor(callback, context) {
    this._callback = callback;
    this._context = context;
  }

  notify(...args) {
    this._callback.call(this._context, ...args);
  }

  isContext(context) {
    return context == this._context;
  }
}

class Event {
  Send(...params) {
    if (this.eventList == null || this.eventList.length <= 0) {
      return false;
    }

    for (var i = 0; i < this.eventList.length; i++) {
      this.eventList[i].notify(...params);
    }

    return true;
  }

  Add(listener) {
    if (this.eventList == null) {
      this.eventList = [];
    }

    if (this.eventList.indexOf(listener) >= 0) {
      return false;
    }

    this.eventList.push(listener);
    return true;
  }

  Remove(context) {
    if (this.eventList == null || this.eventList.length <= 0) {
      return;
    }

    this.eventList.forEach((element, index, array) => {
      if (element.isContext(context)) {
        this.eventList.splice(index, 1);
      }
    });
  }

  RemoveAll() {
    if (this.eventList == null || this.eventList.length <= 0) {
      return;
    }

    this.eventList = [];
  }
}

export { EventManager };
